﻿#include <fstream>  
#include <iostream>  
#include <sstream>
#include <string>

#include <CString>
#include <windows.h>

/* log */
#include "minilog_static.hxx"

#ifdef __cplusplus
extern "C" {
#endif

    // C code...
#include <stdio.h>
#include "ControlCAN.h"
#include "cJSON.h"

#ifdef __cplusplus
}
#endif

#include "can_api.h"


using std::stoi;
using std::stringstream;
using std::ifstream;
using std::ofstream;

string hex_to_str(unsigned int  hex)
{
    char buff[64];
    sprintf(buff, "0x%x", hex);
    return string(buff);
}

string int_to_str(unsigned int  val)
{
    char buff[64];
    sprintf(buff, "%d", val);
    return string(buff);
}

string gen_return_value(struct canConfig *config)
{
    static string retstr;
    string status_str; 
    string data_str, datas_str;
    int i;

    if(config->status == STATUS_ERR)
    {
        status_str = "err";
    }else
    {
        status_str = "ok";
    }

    if(config->action == ACTION_CAN_SEND)
    {
        retstr = "{\n\"action\" : \"send\",\n\"status\" : \"" + status_str +"\"\n}";
    }else if (config->action == ACTION_CAN_RECV)
    {
        if(config->status == STATUS_ERR)
        {
            retstr = "{\n\"action\" : \"recv\",\n\"status\" : \"" + status_str +"\"\n}";
        }else if(config->status == STATUS_OK)
        {
            retstr = "{\n\"action\" : \"recv\",\n\"status\" : \"" + status_str +"\",\n" 
            + "\"can_id\" : " + "\"" + hex_to_str(config->canId) +"\",\n" 
            + "\"data_len\" : " + int_to_str(config->dataLen) + ",\n";
            datas_str = "\"datas\" : [";
            for(i = 0; i < (config->dataLen); i++)
            {
                data_str = hex_to_str(config->datas[i]);

                data_str = "\"" + data_str +"\"";
                if(i + 1 != config->dataLen)
                {
                    data_str = data_str + ",";
                }
                datas_str = datas_str + data_str;
            }
            datas_str = datas_str + "]";
            retstr = retstr + datas_str + "\n}";
        }

    }
    //LogD(retstr);
    return retstr;
}

int do_config_action(struct canConfig *config)
{
    int ret;

    config->status = STATUS_OK;

    if(config->action == ACTION_CAN_SEND)
    {
        ret = can_box_send_data_to_channel(config->canCh, config->canId, config->datas, config->dataLen);
        if(ret != 0)
        {
            //LogE("send failed");
            config->status = STATUS_ERR;
        }
    }else
    {
        ret = can_box_recv_data_from_channel(config->canCh, &config->canId, config->datas, &config->dataLen);
        if(ret == 0)
        {
            //LogE("recv failed");
            config->status = STATUS_ERR;
            ret = STATUS_ERR;
        }
        ret = 0;
    }

    return ret;
}

int parse_json_to_can_config(char * data, struct canConfig *config)
{
    int ret = -1;
    int i, ArrLen;
    string strValue;
    //string recv_str;
    if(!data) return -1;
    if(!config) return -1;

    //1. 载入JSON数据
    cJSON* root = cJSON_Parse(data);
    if (root == NULL)
    {
        printf("Not json format\n");
        printf("--[%s]\n", data);
        return -1;
    }

    //2. 解析字段
    cJSON* item;
    //cJSON* sub_item;

    // 解析用的是第几个CAN盒子（默认是第0个，如果只接一个USB CAN盒子，）
    item = cJSON_GetObjectItem(root, "usb_can_box_id");
    if (item == NULL)
    {
        config->canBoxID = CAN_BOX0;
    }

    // 是否要在打开USB盒子时，清空已有的帧数据
    item = cJSON_GetObjectItem(root, "usb_can_clear_when_start");
    if (item == NULL)
    {
        config->clearBuffWhenStart = 0;
    }
    /*
     send

        请求：
            {
                "action" : "send",

                "usb_can_box_id" : 0,

                "baund_rate" : 250,

                "usb_can_ch" : 0,

                "can_id" : "0x001",

                "data_len" : 8,

                "datas" : ["0x11", "0x12", "0x13", "0x14", "0x15", "0x16", "0x17", "0x18"]
            }

        应答：
            成功：
                {
                    "action" : "send",
                    "status" : "ok",
                }
            失败：
                {
                    "action" : "send",
                    "status" : "err",
                }
    */
    // 解析CAN盒子通道
    item = cJSON_GetObjectItem(root, "usb_can_ch");
    if (item == NULL)
    {
        goto end;
    }
    config->canCh = ( enum CAN_CHANNEL )item->valueint;

    // 解析波特率
    item = cJSON_GetObjectItem(root, "baund_rate");
    if (item == NULL)
    {
        goto end;
    }
    config->baundRate = item->valueint;

    // 解析行为
    item = cJSON_GetObjectItem(root, "action");
    if (item == NULL)
    {
        goto end;
    }
    if(item->valuestring[0] == 's')
    {
        config->action = ACTION_CAN_SEND;
        // 解析CAN id
        item = cJSON_GetObjectItem(root, "can_id");
        if (item == NULL)
        {
            goto end;
        }
        config->canId = stoi(item->valuestring, 0, 16);

        // 解析 Data Len
        item = cJSON_GetObjectItem(root, "data_len");
        config->dataLen = item->valueint;
        if(config->dataLen > 8 || config->dataLen < 0)
        {
            goto end;
        }

        // 解析 CAN data
        item = cJSON_GetObjectItem(root, "datas");
        
		//获取数组大小
		ArrLen = cJSON_GetArraySize(item);
        if(config->dataLen != ArrLen)
        {
            goto end;
        }

		for (i = 0; i < ArrLen; i++)
		{
			//获取数组元素item
			cJSON * ArrNumEle = cJSON_GetArrayItem(item, i);
			if(NULL == ArrNumEle)
			{
			    continue;
			}
			//从item获取值
			//printf("value[%d] : [%s]\n", i, ArrNumEle->valuestring);
            config->datas[i] = stoi(ArrNumEle->valuestring, 0, 16);
		}
        ret = 0;
        goto end;
    }else if(item->valuestring[0] == 'r')
    {
        config->action = ACTION_CAN_RECV;
        ret = 0;
        goto end;
    }

end:
    if(root)
    {
        cJSON_Delete(root);
    }
    
    return ret;
}

void json_str_to_file(string sss, char * file_name)
{
    string write_file_name = string(file_name);
    ofstream os;     //创建一个文件输出流对象
    os.open(write_file_name, ios::trunc);//将对象与文件关联
    //cout<<"向文本中写入内容！"<<endl;
    os<<sss;   //将输入的内容放入txt文件中
    os.close();
}

const char * json_str_from_file(char * file)
{
    static string str;
    ifstream fs(file, ios::binary);
    stringstream ss ;     
    ss << fs.rdbuf();
    fs.close();
    str = ss.str();//read into string
    return str.c_str();
}

void dump_can_config(struct canConfig *config)
{
    int i;
    string hex_str;
    LogD("CAN BOX   :", config->canBoxID);
    LogD("CAN CH    :", config->canCh);
    LogD("BaundRate :",  config->baundRate, "Kbps");

    if(config->action == ACTION_CAN_RECV)
    {
        LogD("Action    : RECV");
    }else if(config->action == ACTION_CAN_SEND)
    {
        LogD("Action    : Send [", config->dataLen, "] Byte(s)");
        for(i = 0; i < config->dataLen; i++)
        {
            hex_str = hex_to_str(config->datas[i]);
            LogD(hex_str);
        }
    }
}


void debug_gen_send_config(struct canConfig *config, int status)
{
    config->status = status;
    config->action = ACTION_CAN_SEND;
}

void debug_gen_recv_config(struct canConfig *config, int status)
{
    int i;
    config->status = status;
    config->action = ACTION_CAN_RECV;
    if(status == STATUS_OK)
    {
        config->dataLen = 8;
        for(i = 0; i < config->dataLen; i++)
        {
            config->datas[i] = 0xf0 + i;
        }
    }
}

/*
./can_rw.exe  action.json [respond.json]


参数 1：请求的json

参数2 ：如果提供此参数，则得到的结果会保存为json文件，否则打印在屏幕中。
*/
int main(int argc, char* argv[])
{
    struct canConfig can_config;
    string ret_json;
    int ret;
    char *data;
    LogInit(MiniLog::DEBUG);

    // 需要至少传递参数1，作为解析
    if(argc == 1)
    {
        return -1;
    }
    data = (char*)json_str_from_file(argv[1]);
    // 解析文件
    if(data == NULL)
    {
        return -2;
    }
    ret = parse_json_to_can_config(data, &can_config);
    if(ret != 0)
    {
        return -3;
    }
    dump_can_config(&can_config);

    ret = init_dll();
    if (STATUS_ERR == ret)
    {
        goto donothing;
    }

    ret = can_box_ch_init(&can_config);
    if (STATUS_ERR == ret)
    {
        goto end;
    }

#if 0
    // 测试自己构造的数据
    debug_gen_send_config(&can_config, STATUS_ERR);
    gen_return_value(&can_config);

    debug_gen_send_config(&can_config, STATUS_OK);
    gen_return_value(&can_config);

    debug_gen_recv_config(&can_config, STATUS_ERR);
    gen_return_value(&can_config);

    debug_gen_recv_config(&can_config, STATUS_OK);
    gen_return_value(&can_config);
#else
    ret = do_config_action(&can_config);
#endif
    ret_json = gen_return_value(&can_config);
    // 如果提供了参数2，那么将结果写入指定的文件中
    if(argc == 3)
    {
        json_str_to_file(ret_json, argv[2]);
    }else
    {
        printf("%s", ret_json.c_str());
    }
    
    //LogD("All done");
    //exit_with = STATUS_OK;
end:
    deinit_dll();
donothing:
    return ret;
}
